Ce projet est réalisé par Lili Schmidlin dans le cadre du module IG (Interfaces Graphiques)
durant la seconde année de DUT Informatique.
Le but est de reproduire un tableau à l'aide d'objets 3D grâce à la librairie
Three.js.
Pour ma part, j'ai choisi de reproduire le tableau intitulé Les valeurs personnelles de
René Magritte
Le tableau est centré sur l’hypertrophie des objets.
L'échelle des objets représentés est modifiée.
Le tableau contient les objets suivants : un verre, un peigne, une allumette, un blaireau et un savon.
Ce tableau contient de nombreux aspects intéressants : textures, reflets, volumes et reliefs.
Ci-dessous, à gauche la reproduction 3D du tableau que j'ai réalisé et à droite l'image originale.
En dessous des 2 tableaux, se trouvent les explications sur la conception du tableau 3D.
Objets de la scène
Pour commencer, j'ai importé les fichiers
".obj" nécessaires.
Parmi ces objets, j'ai construit le blaireau et le savon à l'aide des logiciels paint3D et
Blender.
Le lit, l'armoire, le peigne et le verre sont des fichiers ".obj" que j'ai trouvé sur le site
Free3D.
J'ai ensuite réalisé les éléments que je pouvais créer moi-même via des
box et des
sphères qui sont des primitives fournies par Three.js.
L'allumette est formée par une BoxGeometry associée à une SphereGeometry.
Le petit tapis est également une box, tout comme les 2 plaques qui forment les miroirs de l'armoire.
Pour éviter le
z-fighting, le petit tapis est placé une unité plus haute que le grand.
Plaquage de texture
Une fois l'ensemble des objets importés, grâce à des
OBJLoader, je leur ai appliqué des textures.
Le
plaquage de texture se fait de différentes manières.
Pour le lit, l'armoire et le savon, l'ajout de texture s'est fait à l'aide d'un
MLTLoader.
Les fichiers
.mlt sont des fichiers associés aux modèles obj.
Ils déterminent les textures et matériaux des objets. Les caractères diffus, spéculaires et émissifs sont définis dans
ces fichiers. Ils peuvent faire appel à des images, comme pour le bois du lit et de l'armoire
qui correspond à une image stockée dans le répertoire res (oak.jpg).
Une autre manière d'appliquer une texture à un obj, est d'utiliser un constructeur de
Material.
Il en existe différents types. On utilisera un
MeshPhongMaterial pour le verre, mais un
MeshLambertMaterial pour les tapis,
l'allumette, les miroirs et les murs.
Tandis que l'allumette ne dépend que d'une
couleur, les murs et les tapis utilisent l'attribut
map dont la valeur sera une variable obtenue par chargement d'une
texture image,
grâce à un
TextureLoader.
La seule différence entre les 2 est la manière de les construire. On a vu que le petit était une box, le grand quant à lui,
est défini par des
coordonnées pures. L'attribut
uv est également spécifié afin de pouvoir changer la partie de texture utilisée.
Dans notre cas, on utilise l'ensemble de la texture, mais si on avait à utiliser seulement une
section de la texture, il suffirait
de changer les coordonnées du tableau d'uv de la fonction buildBigCarpet.
Dans le cas des miroirs, l'attribut associé au MeshLambertMaterial sera
envMap. Sa valeur est un objet du
type
WebGLCubeRenderTarget.texture. L'affichage du reflet est réalisé via un objet du type
CubeCamera. Le
near et le
far de cette caméra,
ainsi que sa position, sont déterminés afin de voir le savon qui est au-devant de la scène, tout en n'affichant
pas l'intérieur de l'armoire.
Les attributs du MeshPhongMaterial du verre sont une couleur et une
brillance :
shininess.
Cet attribut définit le reflet de la lumière dans le verre.
La construction du blaireau m'a demandé quelque temps. L'effet métallisé du manche et les poils ne sont pas
facilement réalisables avec Three.js.
Pour le manche, j'ai opté pour un matériau du type
MeshPhysicalMaterial, dont j'ai défini manuellement les propriétés, telle que
la propriété
metalness qui permet de donner l'effet brillant.
Le reflet est possible grâce à un
CubeTextureLoader (même constructeur que pour la skybox expliquée ci-dessous) et la propriété
envMap.
Les poils sont un obj importé et possédant un matériau réalisé avec Blender. Ils ont été créés à l'aide du mode
particules hair de Blender.
Ils ne sont pas très discernables de loin, d'où le mode
"vue sur pinceau qui permet de se rapprocher et de voir les poils en détails.
Skybox
L'ensemble des éléments sont contenus dans une
skybox. Les images qui la composent sont celles
chargées sur les murs et le sol de la scène, stockées dans le répertoire rep.
La
fenêtre sur l'image de droite a été réalisée sur le logiciel de traitement d'images
Gimp.
Utilisation des shaders
Le peigne est chargé par un
OBJLoader. Cependant, la texture qui lui est appliquée est
créée grâce à des
shaders.
Pour cela, on définit, dans le fichier HTML, les données du shader : le
vertex shader et le
fragment shader.
Le fragment shader contient la
fonction de bruit qui sera à l'origine des
motifs et mouvements
sur le peigne. Dans le fichier JavaScript, via la fonction
loadShader, on charge les
shaders définis dans le HTML, puis, à partir des données reçues, on créer le matériau qui sera appliqué au peigne.
Tweening et texture transparante
J'ai ajouté au mur en face de la scène, des nuages
mobiles. L'image de nuage est appliquée sur un
PlaneGeometry,
de la même manière que la texture des tapis. Cependant, l'image contient du transparent. Pour que Three.js le prenne en compte,
il faut mettre à true, l'attribut
transparent du matériau au moment de sa définition.
Pour le déplacement des nuages, j'utilise du
tweening. Les variables
tweenDebut et
tweenFin permettent de définir le
mode de tweening, et fait appel aux variables fonctions
updateAller et
updateRetour. Ces dernières permettent le changement
de position suivant une vitesse aléatoire et différente pour chaque nuage (contenue dans le tableau
speed).
La mise à jour du tweening se fait dans la fonction animate.
Le panel de contrôle est disponible grâce à la librairie dat.gui.
Via ce panel, l'utilisateur peut interagir avec la scène et les objets.
Les valeurs des sliders et des checkbox que l'utilisateur modifie sont récupérés dans la fonction render.
Suivant la valeur du boolean formé par la variable effectController et l'attribut associé, les positions,
tailles et couleurs des objets sont modifiés.
Axes
Pour commencer, il peut afficher les
3 axes directionnels : x, y et z.
La légende des 3 axes est disponible au-dessus du canvas, aux côtés du panel de statistiques. Ce dernier fournit
le nombre de
FPS de la scène.
À noter que ce sont autour de ces 3 axes que sont réalisées les rotations des objets. C'est suivant les
coordonnées x, y et z que sont placés les objets et que sont définies leurs dimensions.
Contrôle des murs
Les contrôles permettent également de jouer sur l'affichage des
4 murs.
Si une des checkbox des murs individuels est cochée, celle liée à l'ensemble des murs ne sera par disponible.
Si aucune des checkbox (droite, gauche, face et arrière) n'est cochée, alors celle liée aux 4 murs pourra être activée.
La disparition/apparition des murs se fait grâce à une
modification dynamique de leur taille et de leur position.
La méthode
animate écoute la scène continuellement. Elle appelle la méthode
render chargée de
mettre à jour les positions, et autres attributs des objets.
Suivant la position de chaque mur, le programme
incrémentera ou
décrémentera
les attributs nécessaires pour faire descendre ou monter les murs. C'est de l'
animation incrémentale.
Mode déplacement, plein-écran et point de vue
Deux modes sont disponibles. Le mode
"Deplacement", qui permet de déplacer à sa guise l'ensemble des objets de la scène.
Cela est réalisable grâce à des
EventsControls.
A noter que je passe par des
objects 3D composés des objets à déplacer et des box dont le matériau est
invisible.
Sans cela, les points d'ancrage de la souris lors des déplacements, ne seraient pas sur l'objet. De plus, cela est plus
pratique pour déplacer les objets formés par plusieurs sous objets (tels que l'allumette ou la zone pinceau/armoire)
Les types d'évènements (
mouseOut, dragAndDrop et mouseOver), sont paramétrés. Suivant l'action de l'utilisateur
(survol, clic ou déplacement), le
curseur de la souris changera. Néanmoins, l'utilisateur ne
peut déplacer les objets uniquement selon leur positon
x et z. Leur hauteur restera inchangée.
La désactivation du contrôle caméra est également réalisée, afin de ne pas perturber le déplacement des objets.
PS : Si l'on tente de déplacer l'armoire en cliquant sur les poils du pinceau, la fenêtre risque de ne plus répondre...
(à cause de la taille de l'obj que représente les poils...)
Un mode de visualisation du type
"plein-écran" est disponible. Une fois la case cochée, la scène est agrandie.
Elle occupe l'ensemble de la largeur et de la hauteur de la fenêtre.
Pour cela, les dimensions du renderer seront
window.innerWidth pour la larguer et
window.innerHeight
pour la hauteur.
Enfin, il est possible de changer de
point de vue que l'on a sur la scène.
Le premier mode de changement est celui qui permet de voir le pinceau plus en
détails.
Pour les changements de points de vue, il est nécessaire de passer par une
variable intermédiaire qui indique
si le point de vue a été activé. Sans cela, le programme ne gère pas correctement le contrôle de la caméra.
La seconde précaution à prendre est le
détachement des évènements de déplacement. Ils entraînaient également
un dysfonctionnement du contrôle caméra.
Pour le changement de position de la caméra et celui de l'endroit observé il suffit de mettre à jour les
positions en fonction de celle de l'objet. Si la position de la
caméra et celle de la
cible, ne sont pas en fonction
de l'
objet 3D concerné (object3DBed et object3DCloset), après les déplacements, l'
angle de vue sur l'objet ne serait plus le bon.
Dans le cas du mode où l'utilisateur à l'impression d'être sur le lit, je change la
fov (field of view)
que j'élargie afin d'avoir un meilleur aperçu de l'ensemble de la pièce.
L'appel de la méthode
updateProjectionMatrix sur la caméra permet d'enregistrer les modifications effectuées sur la caméra.
Couleurs et motifs du peigne
Le dossier suivant concerne les paramètres du peigne. Le slide
"Kd" permet de définir si le peigne sera sombre, ou si au contraire,
il donnera l'impression d'
émettre de la lumière.
Les sliders d'après sont pour modifier le
motif du peigne, puis sa
couleur.
Lumières de la scène
L'utilisateur peut également changer la position ainsi que la couleur de la lumière du type
PointLight.
Initialement, elle est située devant la fenêtre fictive.
À noter que la scène est constituée de 2 autres types de lumières : une
AmbientLight et une
DirectionalLight.
La première permet uniquement d'éviter les
zones mortes. Les positions des lumières ponctuelles et directionnelles
sont consultables grâce à la checkbox
"Helper" du dossier "Lumière".
Réinitialisation
Enfin, le dossier
"Réinitialisation" du panel de contrôle contient les checkbox pour réinitialiser :
- la position de la caméra
- la position des objets
- la couleur et le motif du peigne
- la couleur et la position de la lumière